/**
 * 统一请求封装
 * 自动处理 token、错误、重试、超时等
 */

import { BASE_URL } from '../utils/config.js'

// 请求配置
const REQUEST_CONFIG = {
  timeout: 30000, // 30秒超时
  maxRetries: 2,  // 最大重试次数
  retryDelay: 1000 // 重试延迟 1秒
}

// 错误码映射
const ERROR_CODES = {
  401: '登录已过期，请重新登录',
  403: '权限不足',
  404: '请求的资源不存在',
  500: '服务器内部错误',
  502: '网关错误',
  503: '服务暂不可用',
  504: '网关超时'
}

// 请求队列（用于防重复请求）
const requestQueue = new Map()

// token刷新状态
let isRefreshing = false
let refreshPromise = null

/**
 * 生成请求唯一标识
 */
function generateRequestKey(url, method, data) {
  return `${method}:${url}:${JSON.stringify(data || {})}`
}

/**
 * 显示错误提示
 */
function showError(message, duration = 2000) {
  uni.showToast({
    title: message,
    icon: 'none',
    duration
  })
}

/**
 * 显示加载提示
 */
function showLoading(title = '请求中...') {
  uni.showLoading({ title })
}

/**
 * 隐藏加载提示
 */
function hideLoading() {
  uni.hideLoading()
}

/**
 * 获取认证 token
 */
function getAuthToken() {
  return uni.getStorageSync('accessToken') || ''
}

/**
 * 清理登录状态
 */
function clearAuth() {
  uni.removeStorageSync('accessToken')
  uni.removeStorageSync('refreshToken')
  uni.removeStorageSync('userInfo')
  
  // 跳转到登录页
  uni.reLaunch({
    url: '/pages/login/index'
  })
}

/**
 * 刷新token
 */
async function refreshToken() {
  const refreshTokenValue = uni.getStorageSync('refreshToken')
  
  if (!refreshTokenValue) {
    throw new Error('No refresh token found')
  }

  try {
    const response = await uni.request({
      url: `${BASE_URL}/api/wxapp/auth/refresh`,
      method: 'POST',
      data: { refreshToken: refreshTokenValue },
      header: { 'Content-Type': 'application/json' }
    })

    if (response.statusCode === 200 && response.data?.success) {
      const { accessToken, refreshToken: newRefreshToken } = response.data
      
      // 更新本地存储
      uni.setStorageSync('accessToken', accessToken)
      uni.setStorageSync('refreshToken', newRefreshToken)
      
      console.log('[request] Token刷新成功')
      return accessToken
    } else {
      throw new Error('Token刷新失败')
    }
  } catch (error) {
    console.error('[request] Token刷新失败:', error)
    throw error
  }
}

/**
 * 处理响应数据
 */
function handleResponse(response, originalOptions) {
  const { statusCode, data } = response
  
  // HTTP 状态码检查
  if (statusCode === 401) {
    // 401错误，尝试刷新token并重试请求
    return handleUnauthorized(originalOptions)
  }
  
  if (statusCode >= 400) {
    const errorMsg = ERROR_CODES[statusCode] || `请求失败 (${statusCode})`
    showError(errorMsg)
    return Promise.reject(new Error(errorMsg))
  }
  
  // 业务逻辑检查
  if (data && typeof data === 'object') {
    if (data.success === false) {
      const errorMsg = data.message || '操作失败'
      showError(errorMsg)
      return Promise.reject(new Error(errorMsg))
    }
    
    return data
  }
  
  return data
}

/**
 * 处理401未授权错误
 */
async function handleUnauthorized(originalOptions) {
  // 如果是刷新token的请求失败了，直接清理登录状态
  if (originalOptions?.url?.includes('/api/wxapp/auth/refresh')) {
    console.log('[request] Refresh token失效，清理登录状态')
    clearAuth()
    return Promise.reject(new Error('Refresh token expired'))
  }

  // 登录/注册/资料类接口的401不应触发刷新逻辑，直接透传错误给业务方
  const url = originalOptions?.url || ''
  if (
    url.includes('/api/wxapp/auth/wechat-login') ||
    url.includes('/api/wxapp/auth/login') ||
    url.includes('/api/wxapp/auth/register') ||
    url.includes('/api/wxapp/auth/profile')
  ) {
    return Promise.reject(new Error('Unauthorized'))
  }

  // 如果本地没有 refreshToken，避免触发刷新流程并返回更清晰的未登录错误
  try {
    const storedRefresh = uni.getStorageSync('refreshToken')
    if (!storedRefresh) {
      clearAuth()
      return Promise.reject(new Error('Unauthorized'))
    }
  } catch (e) {
    clearAuth()
    return Promise.reject(new Error('Unauthorized'))
  }

  // 如果已经在刷新token，等待刷新完成
  if (isRefreshing) {
    try {
      await refreshPromise
      // 刷新完成后，用新token重试原请求
      return retryOriginalRequest(originalOptions)
    } catch (error) {
      clearAuth()
      return Promise.reject(error)
    }
  }

  // 开始刷新token
  isRefreshing = true
  refreshPromise = refreshToken()
    .then((newAccessToken) => {
      isRefreshing = false
      refreshPromise = null
      return newAccessToken
    })
    .catch((error) => {
      isRefreshing = false
      refreshPromise = null
      clearAuth()
      throw error
    })

  try {
    await refreshPromise
    // 刷新成功，重试原请求
    return retryOriginalRequest(originalOptions)
  } catch (error) {
    return Promise.reject(error)
  }
}

/**
 * 重试原始请求
 */
async function retryOriginalRequest(originalOptions) {
  if (!originalOptions) {
    return Promise.reject(new Error('No original request options'))
  }

  // 更新请求头中的token
  const newToken = getAuthToken()
  if (newToken) {
    originalOptions.header = originalOptions.header || {}
    originalOptions.header.Authorization = `Bearer ${newToken}`
  }

  try {
    const response = await uni.request(originalOptions)
    return handleResponse(response, originalOptions)
  } catch (error) {
    throw error
  }
}

/**
 * 延迟函数
 */
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

/**
 * 执行请求（支持重试）
 */
async function executeRequest(options, retryCount = 0) {
  try {
    const response = await uni.request(options)
    return handleResponse(response, options)
  } catch (error) {
    console.error(`请求失败 (尝试 ${retryCount + 1}/${REQUEST_CONFIG.maxRetries + 1}):`, error)
    
    // 如果还有重试次数
    if (retryCount < REQUEST_CONFIG.maxRetries) {
      await delay(REQUEST_CONFIG.retryDelay)
      return executeRequest(options, retryCount + 1)
    }
    
    // 重试次数用完，返回错误
    const errorMsg = error.message || '网络请求失败'
    showError(errorMsg)
    throw error
  }
}

/**
 * 通用请求方法
 */
async function request(options = {}) {
  const {
    url,
    method = 'GET',
    data,
    header = {},
    showLoading: shouldShowLoading = false,
    preventDuplicate = true,
    ...restOptions
  } = options
  
  // 生成完整的 URL
  const fullUrl = url.startsWith('http') ? url : `${BASE_URL}${url}`
  
  // 防重复请求检查
  const requestKey = generateRequestKey(fullUrl, method, data)
  if (preventDuplicate && requestQueue.has(requestKey)) {
    console.warn('重复请求被阻止:', requestKey)
    return requestQueue.get(requestKey)
  }
  
  // 构建请求头
  const requestHeader = {
    'Content-Type': 'application/json',
    ...header
  }
  
  // 添加认证 token
  const token = getAuthToken()
  if (token) {
    requestHeader.Authorization = `Bearer ${token}`
  }
  
  // 构建请求选项
  const requestOptions = {
    url: fullUrl,
    method: method.toUpperCase(),
    data,
    header: requestHeader,
    timeout: REQUEST_CONFIG.timeout,
    ...restOptions
  }
  
  // 显示加载提示
  if (shouldShowLoading) {
    showLoading()
  }
  
  // 创建请求 Promise
  const requestPromise = executeRequest(requestOptions)
  
  // 添加到请求队列
  if (preventDuplicate) {
    requestQueue.set(requestKey, requestPromise)
  }
  
  try {
    const result = await requestPromise
    return result
  } finally {
    // 清理请求队列
    if (preventDuplicate) {
      requestQueue.delete(requestKey)
    }
    
    // 隐藏加载提示
    if (shouldShowLoading) {
      hideLoading()
    }
  }
}

/**
 * GET 请求
 */
export function get(url, params, options = {}) {
  let fullUrl = url
  if (params && Object.keys(params).length > 0) {
    const queryString = Object.keys(params)
      .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
      .join('&')
    fullUrl += (url.includes('?') ? '&' : '?') + queryString
  }
  
  return request({
    url: fullUrl,
    method: 'GET',
    ...options
  })
}

/**
 * POST 请求
 */
export function post(url, data, options = {}) {
  return request({
    url,
    method: 'POST',
    data,
    ...options
  })
}

/**
 * PUT 请求
 */
export function put(url, data, options = {}) {
  return request({
    url,
    method: 'PUT',
    data,
    ...options
  })
}

/**
 * DELETE 请求
 */
export function del(url, options = {}) {
  return request({
    url,
    method: 'DELETE',
    ...options
  })
}

/**
 * 上传文件
 */
export function upload(url, filePath, options = {}) {
  const {
    name = 'file',
    formData = {},
    showLoading: shouldShowLoading = true,
    ...restOptions
  } = options
  
  const fullUrl = url.startsWith('http') ? url : `${BASE_URL}${url}`
  
  // 添加认证 token
  const token = getAuthToken()
  const header = {}
  if (token) {
    header.Authorization = `Bearer ${token}`
  }
  
  // 记录是否真正显示了loading
  let loadingShown = false
  
  if (shouldShowLoading) {
    try {
      showLoading('上传中...')
      loadingShown = true
    } catch (error) {
      console.warn('显示loading失败:', error)
      loadingShown = false
    }
  }
  
  return new Promise((resolve, reject) => {
    uni.uploadFile({
      url: fullUrl,
      filePath,
      name,
      formData,
      header,
      timeout: REQUEST_CONFIG.timeout,
      ...restOptions,
      success: (response) => {
        try {
          console.log('上传响应原始数据:', response)
          
          // 处理上传文件的特殊响应格式
          let processedResponse = response
          if (typeof response.data === 'string') {
            try {
              processedResponse = {
                ...response,
                data: JSON.parse(response.data)
              }
              console.log('解析后的响应数据:', processedResponse)
            } catch (parseError) {
              console.error('响应数据解析失败:', parseError)
              console.log('原始响应数据:', response.data)
            }
          }
          
          const result = handleResponse(processedResponse)
          resolve(result)
        } catch (error) {
          reject(error)
        }
      },
      fail: (error) => {
        console.error('上传失败:', error)
        showError('上传失败')
        reject(error)
      },
      complete: () => {
        // 只有真正显示了loading才隐藏
        if (loadingShown) {
          try {
            hideLoading()
          } catch (error) {
            console.warn('隐藏loading失败:', error)
          }
        }
      }
    })
  })
}

// 导出请求方法
export default request

// 导出工具方法
export {
  showError,
  showLoading,
  hideLoading,
  getAuthToken,
  clearAuth,
  REQUEST_CONFIG
}